package com.recipe.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.recipe.common.config.CustomNameThreadFactory;
import com.recipe.common.config.RedisUtil;
import com.recipe.entity.*;
import com.recipe.entity.vo.RankVo;
import com.recipe.mapper.DishMapper;
import com.recipe.service.*;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * (Dish)表服务实现类
 *
 * @author lzk
 * @since 2024-06-17 15:23:24
 */
@Service("dishService")
@RequiredArgsConstructor
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
    public static final String DISH_KEY = "dish:";
    public static final String DISH_DETAIL_KEY = "dishDetail:";

    public static final String RANK_KEY="RANK:";
    private final RedisUtil redisUtil;
    private final DishSourceService dishSourceService;
    private final DishStepService dishStepService;
    private final UserService userService;
    private final DishLabelService dishLabelService;

    @Override
    public List<Dish> getAll() {
        String dishes = redisUtil.get(DISH_KEY);
        if(!StringUtils.isBlank(dishes)){
            List<Dish> dishList = JSON.parseArray(dishes, Dish.class);
            return dishList;
        }else{
            List<Dish> dishList = baseMapper.selectList(null);

            dishList.forEach(dish-> {
                dish.setLabelName(findLabel(dish));
                dish.setNickName(userService.getById(dish.getUserid()).getNickname());
            });
            redisUtil.setNx(DISH_KEY,JSON.toJSONString(dishList),300l,TimeUnit.SECONDS);

            return dishList;
        }

    }
    private String findLabel(Dish dish){

        DishLabel label = dishLabelService.getById(dish.getLabelid());

    return label.getLabelname();
    }
    @Override
    public List<Dish> getBySource(String dishSource){
        String[] source = dishSource.split(",");
        log.info("source:{}",source.toString());
        List<Dish> dishList = this.getAll();
        List<Dish> filteredDishList = dishList.stream()
                .filter(dish -> Arrays.stream(source).anyMatch(dish.getSourceFood()::contains))
                .collect(Collectors.toList());

       return filteredDishList;
    }

    @Override
    public Dish getDishById(Long id) {
        if(redisUtil.exist(DISH_KEY+id)){
            String dish = redisUtil.get(DISH_KEY+id);
            Dish dish1 = JSON.parseObject(dish, Dish.class);
            return dish1;
        }else{
            Dish dish = baseMapper.selectById(id);
            dish.setLabelName(findLabel(dish));
            Long time=180+(long)(Math.random()*120);
            redisUtil.setNx(DISH_KEY+id,JSON.toJSONString(dish),time,TimeUnit.SECONDS);
            return dish;
        }

    }

    @Override
    @SneakyThrows
    public Dish getDetailDish(Long id) {
        String dishDetail = redisUtil.get(DISH_DETAIL_KEY + id);

        Dish dish=new Dish();
        if(dishDetail!=null){
            dish = JSON.parseObject(dishDetail, Dish.class);

        }else{
            dish = this.getDishById(id);



            List<DishStep> dishSteps = dishStepService.getByDishId(id);
            dishSteps.stream().sorted(Comparator.comparing(DishStep::getStepNumber)).collect(Collectors.toList());
            List<DishSource> dishSources = dishSourceService.getByDishId(id);


            dish.setDishSources(dishSources);
            dish.setDishSteps(dishSteps);
            Long time=180+(long)(Math.random()*120);


            redisUtil.setNx(DISH_DETAIL_KEY + id, JSON.toJSONString(dish), time, TimeUnit.SECONDS);

        }
        return dish;


    }

    @Override
    public User getauthor(Long userid) {
        return userService.getById(userid);
    }

    @Override
    @Transactional
    public void add(Dish dish) {
        String username = dish.getUsername();
        User user =userService.getUserByUserName(username);
        Long userId = user.getId();
        dish.setUserid(userId);
        dish.setIsDeleted(0);
        String labelName = dish.getLabelName();
        LambdaQueryWrapper<DishLabel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DishLabel::getLabelname,labelName);
        DishLabel one = dishLabelService.getOne(queryWrapper);
        dish.setLabelid(one.getId());
        baseMapper.save(dish);
        long id =dish.getId();

        redisUtil.addScore(RANK_KEY,String.valueOf(userId),1);
        dish.setUserid(userId);
        dish.setIsDeleted(0);



        List<DishStep> dishSteps = dish.getDishSteps();
        dishSteps.forEach(dishStep -> {
            dishStep.setDishid(id);
            dishStepService.save(dishStep);
        });

        List<DishSource> dishSources = dish.getDishSources();

        dishSources.forEach(dishSource -> {
            dishSource.setDishid((long)id);
            dishSourceService.save(dishSource);
        });

    }


     public List<RankVo>  getContributeList(){
         Set<ZSetOperations.TypedTuple<String>> typedTuples = redisUtil.rankWithScore(RANK_KEY, 0, 10);
         if (log.isInfoEnabled()) {
             log.info("getContributeList.typedTuples:{}", JSON.toJSONString(typedTuples));
         }
         if (CollectionUtils.isEmpty(typedTuples)) {
             return Collections.emptyList();
         }
         List<RankVo> rankVos = new LinkedList<>();

         typedTuples.forEach((typedTuple -> {
             String value = typedTuple.getValue();
             log.info(value);
             Long id = Long.valueOf(value);



             User user = userService.getById(id);
             RankVo rankVo=new RankVo();
             rankVo.setScore(typedTuple.getScore().intValue());
             rankVo.setHeadUrl(user.getHeadUrl());
             rankVo.setNickName(user.getNickname());

             rankVos.add(rankVo);

         }));
         return rankVos;

     }

    @Override
    public List<Dish> getPersonDish(String username) {
        User user = userService.getUserByUserName(username);
        Long userId = user.getId();
        List<Dish> personDish = this.getAll().stream().filter(dish -> dish.getUserid().equals(userId)).collect(Collectors.toList());
        return personDish;
    }


}

